import Link from './krouter-link'
import View from './krouter-view'

let Vue

// 1.实现一个插件：挂载$router，目的就是把router的实例挂载到prototype上，实现全局访问，install方法

class KVueRouter {
  constructor(options) {
    this.$options = options
    console.log(this.$options)

    // 核心：需要创建响应式的current属性
    // 利用Vue提供的defineReactive做响应化
    // 这样将来current变化的时候，依赖的组件会重新render
    // 指定对象，属性，默认值
    // Vue.util.defineReactive(this, 'current', '/')
    // 整一个match数组做响应式
    this.current = window.location.hash.slice(1) || '/'
    Vue.util.defineReactive(this, 'matched', [])
    // match方法递归的遍历路由表获取包含指定关系的数组
    this.match()
    // this.app = new Vue({
    //   data() {
    //     return {
    //       current: '/'
    //     }
    //   }
    // })

    // 3. 监控url变化
    window.addEventListener('hashchange', this.onHashChange.bind(this))
    // 用户刷新之后出发load事件，监听load事件，避免this变成window
    // this.onHashChange.bind(this)可以替换为 onHashChange = ()={}
    // 没有监听刷新事件的话会默认指向/
    window.addEventListener('load', this.onHashChange.bind(this))

    // 创建一个路由映射表, 以避免每次更新都需要forEach，只需要做一次forEach
    this.routeMap = {}
    options.routes.forEach((route) => {
      this.routeMap[route.path] = route
    })
  }

  onHashChange() {
    console.log(window.location.hash)
    // 有一个#号所以需要截取一下
    this.current = window.location.hash.slice(1)
    // 路径发生变化match的数组需要清空，然后重新匹配
  }
  match(routes) {
    routes = routes || this.$options.routes
    // 递归遍历
    for (const route of routes) {
      if (route.path === '/' && this.current === '/') {
        // 配置的首页被匹配到了
        this.matched.push(route)
        // 不能再首页配置路由嵌套
        return
      }
      // /about/info
      // 如果要检索的字符串值没有出现，则该方法返回 -1。
      if (route.path !== '/' && this.current.indexOf(route.path) != -1) {
        // 配置的首页被匹配到了
        this.matched.push(route)
        // 递归
        if (route.children) {
          this.match(route.children)
        }
        return
      }
    }
  }
}
// 静态方法 Vue构造函数赋值给_Vue
KVueRouter.install = function (_Vue) {
  // 保存构造函数，在KVueRouter里面使用 为什么不import Vue？ 打包就太大了！ 用插件的形式传递进来
  Vue = _Vue

  // 挂载$router
  // 怎么获取根实例中的router选项？
  // mixin混入一个生命周期的钩子，钩子或者方法中就可以获取vue实例了，全局混入Vue.mixin
  // 这里面的钩子会在所有组件中遍历执行
  Vue.mixin({
    beforeCreate() {
      // 确保根实例的时候才执行
      if (this.$options.router) {
        Vue.prototype.$router = this.$options.router
      }
    },
  })

  // 任务2：实现两个全局组件router-link和router-view
  // 不能使用template描述标签，因为打包之后没有编译器无法编译，没有运行时版本
  // 只能使用render函数描述组件
  Vue.component('router-link', Link)
  Vue.component('router-view', View)
}

export default KVueRouter
